from fastapi import FastAPI, Depends, HTTPException, status, Form
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from app import models, database, auth
from app.database import engine, get_db, init_database
from jose import JWTError, jwt
from typing import List, Optional, Dict, Any
from app.models import TimedRoom, RoomStatus
from pydantic import BaseModel, Field, ConfigDict
from datetime import datetime, timedelta, timezone
from fastapi.responses import JSONResponse
import json,math
from decimal import Decimal
from fastapi.staticfiles import StaticFiles
import os
from pathlib import Path
from sqlalchemy import func
import sys
import logging
import traceback
from sqlalchemy.exc import IntegrityError
import textwrap
from win32 import win32print
from app.printer_setting import printer_settings, PrinterConfig
from zoneinfo import ZoneInfo

CHINA_TZ = ZoneInfo("Asia/Shanghai")

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout)
    ]
)

logger = logging.getLogger(__name__)

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super(DecimalEncoder, self).default(obj)

def calculate_overtime_fee(duration: float, minimum_hours: float, overtime_rate: float) -> tuple[float, float]:
    """
    计算超时费用
    
    Args:
        duration: 总使用时长（小时）
        minimum_hours: 最低使用小时数
        overtime_rate: 每小时超时费率
    
    Returns:
        tuple: (超时时长, 超时费用)
    """
    overtime = 0
    overtime_fee = 0
    
    if duration > minimum_hours:
        # 计算超时时间（小时）
        overtime = duration - minimum_hours
        # 向下取整得到完整小时数
        overtime_hours = math.floor(overtime)

        # 计算不足1小时的分钟数
        overtime_minutes = (overtime - overtime_hours) * 60
        
        # 如果小数部分超过15分钟，则超时时间增加1小时
        if overtime_minutes > 15:
            overtime_hours += 1

        overtime_fee = overtime_hours * overtime_rate
    
    return overtime, overtime_fee

def get_string_width(s: str) -> int:
    """
    计算字符串的显示宽度
    中文字符计为2，其他字符计为1
    """
    width = 0
    for c in s:
        width += 2 if '\u4e00' <= c <= '\u9fff' else 1
    return width

def pad_string(s: str, width: int, align: str = 'left') -> str:
    """
    将字符串填充到指定宽度
    align: 'left', 'right', 'center'
    """
    actual_width = get_string_width(s)
    padding = width - actual_width
    
    if padding <= 0:
        return s
        
    if align == 'left':
        return s + ' ' * padding
    elif align == 'right':
        return ' ' * padding + s
    else:  # center
        left_padding = padding // 2
        right_padding = padding - left_padding
        return ' ' * left_padding + s + ' ' * right_padding
    
# 在打印小票的代码中使用
def format_receipt_line(name: str, qty: int, price: float, subtotal: float) -> str:
    name_part = pad_string(name, 16)
    return f"{name_part}x{qty} {price:>6.2f} {subtotal:>6.2f}\n"

try:
    # 获取应用路径
    if getattr(sys, 'frozen', False):
        application_path = sys._MEIPASS
        logger.info(f"Running in PyInstaller bundle. Application path: {application_path}")
    else:
        application_path = Path(__file__).parent
        logger.info(f"Running in development mode. Application path: {application_path}")

    frontend_path = Path(application_path) / 'web'
    logger.info(f"Frontend path: {frontend_path}")
    logger.info(f"Frontend exists: {frontend_path.exists()}")

    init_database()

    app = FastAPI()

    # 先注册所有API路由
    api_app = FastAPI()

    # CORS设置
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[
            "*"  # 允许所有域名访问，仅在开发环境使用
        ],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    # 为api_app也添加相同的CORS中间件
    api_app.add_middleware(
        CORSMiddleware,
        allow_origins=[

            "*"  # 允许所有域名访问，仅在开发环境使用
        ],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    # 将所有API路由挂载到/api前缀下
    app.mount("/api", api_app)

    # 如果前端目录存在，则挂载静态文件
    if frontend_path.exists():
        @app.get("/login")
        async def serve_login():
            """直接返回登录页面"""
            return FileResponse(str(frontend_path / "index.html"))
        
        app.mount("/", StaticFiles(directory=str(frontend_path), html=True), name="static")
        
        @app.get("/{full_path:path}")
        async def serve_frontend(full_path: str):
            file_path = frontend_path / full_path
            if not file_path.exists():
                return FileResponse(str(frontend_path / "index.html"))
            return FileResponse(str(file_path))
    else:
        print(f"Warning: Frontend directory not found at {frontend_path}")

    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")

    # 添加请求模型
    class RoomCreate(BaseModel):
        name: str
        minimum_charge: float
        minimum_hours: float
        overtime_rate: float
        status: str = RoomStatus.AVAILABLE.value

    class RoomUpdate(BaseModel):
        name: str | None = None
        minimum_charge: float | None = None
        minimum_hours: float | None = None
        overtime_rate: float | None = None
        status: str | None = None

    class SnackCreate(BaseModel):
        name: str
        price: float
        cost: float
        stock: int
        unit: str
        category_id: int
        description: Optional[str] = None
        is_active: bool = True

    class SnackUpdate(BaseModel):
        name: Optional[str] = None
        price: Optional[float] = None
        cost: Optional[float] = None
        stock: Optional[int] = None
        unit: Optional[str] = None
        category_id: Optional[int] = None
        description: Optional[str] = None
        is_active: Optional[bool] = None

    class OrderCreate(BaseModel):
        room_id: int

    class OrderItemCreate(BaseModel):
        snack_id: int
        quantity: int = 1  # 默认数量为1

    # 定义响应模型
    class OrderItemHistory(BaseModel):
        id: int
        snack_name: str
        quantity: int
        price: float
        subtotal: float
        created_at: datetime

        class Config:
            from_attributes = True

    class OrderHistory(BaseModel):
        id: int
        room_name: str
        start_time: datetime
        end_time: datetime
        duration: float
        base_amount: float
        items: List[OrderItemHistory]
        snack_amount: float
        total_amount: float

        class Config:
            from_attributes = True

    class CheckoutData(BaseModel):
        adjustment: float = 0
        remark: str = ""

    # 添加新的响应模型
    class OrderItemResponse(BaseModel):
        model_config = ConfigDict(from_attributes=True)
        
        id: int
        order_id: int
        snack_id: int
        quantity: int
        price: float
        created_at: datetime
        snack_name: str | None = None

        def __init__(self, **data):
            super().__init__(**data)
            if hasattr(data.get('snack', {}), 'name'):
                self.snack_name = data['snack'].name

    # 在文件开头的 Pydantic 模型定义部分添加
    class OrderResponse(BaseModel):
        model_config = ConfigDict(from_attributes=True)
        
        id: int
        room_id: int
        start_time: datetime
        end_time: datetime | None
        base_amount: float
        total_amount: float
        status: str

    # 在文件开头的 Pydantic 模型定义部分添加
    class SnackResponse(BaseModel):
        model_config = ConfigDict(from_attributes=True)
        
        id: int
        name: str
        price: float
        cost: float
        stock: int
        unit: str
        category_id: int
        category_name: str | None = None  # 添加分类名称字段
        description: str | None
        is_active: bool

        def __init__(self, **data):
            super().__init__(**data)
            if hasattr(data.get('category', {}), 'name'):
                self.category_name = data['category'].name

    # 添加请求模型
    class StockAdjustment(BaseModel):
        adjustment: int

    # 在文件开头的 Pydantic 模型定义部分添加
    class RoomResponse(BaseModel):
        model_config = ConfigDict(from_attributes=True)
        
        id: int
        name: str
        minimum_charge: float
        minimum_hours: float
        overtime_rate: float
        status: str

    # 添加用户信息响应模型
    class UserResponse(BaseModel):
        username: str

    # 添加分类相关的 Pydantic 模型
    class CategoryCreate(BaseModel):
        name: str

    class CategoryUpdate(BaseModel):
        name: str

    class CategoryResponse(BaseModel):
        model_config = ConfigDict(from_attributes=True)
        id: int
        name: str

    # 添加打印相关的模型
    class PrintReceiptData(BaseModel):
        order_id: int
        items: List[Dict[str, Any]]
        total_amount: float
        room_name: str
        start_time: datetime
        end_time: datetime
        base_amount: float
        snack_amount: float
        adjustment: float = 0
        remark: str = ""

        class Config:
            json_encoders = {
                datetime: lambda v: v.isoformat()
            }

    class PrintLabelData(BaseModel):
        name: str
        price: float
        
    # 修改打印机配置类
    class PrinterConfig(BaseModel):
        name: str  # 打印机名称
        is_default: bool = False

    # 全局打印机配置
    RECEIPT_PRINTER_CONFIG = PrinterConfig(
        name=""  # 初始为空，等待用户选择
    )

    LABEL_PRINTER_CONFIG = PrinterConfig(
        name=""  # 初始为空，等待用户选择
    )

    def get_printer(printer_type: str = "receipt"):
        """获取打印机实例"""
        try:
            config = RECEIPT_PRINTER_CONFIG if printer_type == "receipt" else LABEL_PRINTER_CONFIG
            
            return config.name
        except Exception as e:
            logger.error(f"获取打印机失败: {str(e)}")
            raise

    def get_system_printers():
        """获取系统打印机列表"""
        try:
            printers = []
            # 使用 wmic 命令获取打印机列表
            import subprocess
            
            # 获取所有打印机
            process = subprocess.Popen(
                ['wmic', 'printer', 'get', 'name,default'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                universal_newlines=True
            )
            output, error = process.communicate()
            
            if error:
                logger.error(f"WMIC命令执行错误: {error}")
                return []
            
            # 解析输出
            lines = output.strip().split('\n')
            if len(lines) < 2:  # 至少需要标题行和一个打印机
                return []
            
            # 跳过标题行
            for line in lines[1:]:
                line = line.strip()
                if not line:
                    continue
                    
                # WMIC输出格式: "Default Name"，其中Default是TRUE或FALSE
                parts = line.split()
                if len(parts) >= 2:
                    is_default = parts[0].lower() == 'true'
                    name = ' '.join(parts[1:])  # 打印机名可能包含空格
                    
                    printers.append({
                        "name": name,
                        "is_default": is_default
                    })
            
            return printers
        except Exception as e:
            logger.error(f"获取打印机列表失败: {str(e)}")
            logger.error(f"Error details: {traceback.format_exc()}")
            return []

    def print_raw(printer_name: str, data: bytes) -> bool:
        """
        直接发送原始数据到打印机
        """
        try:
            if not printer_name:
                raise ValueError("打印机名称不能为空")
            logger.info(f"打印机名称: {printer_name}")
            logger.info(f"打印数据:\n {data}")
            # 打开打印机
            handle = win32print.OpenPrinter(printer_name)
            try:
                # 创建打印作业
                job = win32print.StartDocPrinter(handle, 1, ("Label", None, "RAW"))
                try:
                    win32print.StartPagePrinter(handle)
                    win32print.WritePrinter(handle, data)
                    win32print.EndPagePrinter(handle)
                finally:
                    win32print.EndDocPrinter(handle)
            finally:
                win32print.ClosePrinter(handle)
            
            return True
        except Exception as e:
            logger.error(f"打印失败: {str(e)}")
            return False

    def print_receipt(data: PrintReceiptData):
        """打印小票"""
        try:
            printer_config = printer_settings.get_printer_config("receipt")
            if not printer_config or not printer_config.name:
                raise ValueError("请先配置小票打印机")
            
            logger.info(f"打印小票数据: {data}")
            
            # 确保两个时间都是naive datetime
            start_time = data.start_time
            end_time = datetime.now(CHINA_TZ)
            # 如果 start_time 是无时区的，假设它是 UTC 时间并设置时区
            if start_time.tzinfo is None:
                start_time = start_time.replace(tzinfo=CHINA_TZ)
            else:
                start_time = start_time.astimezone(CHINA_TZ)    
            
            # 计算使用时长
            duration_seconds = (end_time - start_time).total_seconds()
            hours = int(duration_seconds // 3600)
            minutes = int((duration_seconds % 3600) // 60)
            duration_str = f"{hours}小时{minutes}分钟"
            
            # 构建打印内容
            content = ""
            content += "\x1B\x40"  # 初始化打印机
            content += "\x1B\x61\x01"  # 居中对齐
            content += "=" * 32 + "\n"
            content += "消费小票\n"
            content += "=" * 32 + "\n"
            content += "\x1B\x61\x00"  # 左对齐
            content += f"{data.room_name}\n"
            content += f"开始时间: {start_time.strftime('%Y-%m-%d %H:%M')}\n"
            content += f"结束时间: {end_time.strftime('%Y-%m-%d %H:%M')}\n"
            content += f"使用时长: {duration_str}\n"
            content += "-" * 32 + "\n"
            content += "商品清单:\n"
            
            # 打印商品列表
            total_snack_amount = 0
            for item in data.items:
                name = item.get('snack_name', '')
                qty = item.get('quantity', 0)
                price = item.get('price', 0)
                subtotal = qty * price
                total_snack_amount += subtotal
                name += "x" + str(qty)
                content += format_receipt_line(name, qty, price, subtotal)
            content += "-" * 32 + "\n"
            content += f"房费: RMB{data.base_amount:>8.2f}\n"
            content += f"商品: RMB{total_snack_amount:>8.2f}\n"
            
            if data.adjustment != 0:
                content += f"调整金额: RMB{data.adjustment:>8.2f}\n"
            
            content += f"总计: RMB{data.total_amount:>8.2f}\n"
            
            if data.remark:
                content += "-" * 32 + "\n"
                content += "备注:\n"
                content += textwrap.fill(data.remark, width=32) + "\n"
            
            content += "=" * 32 + "\n"
            content += "\x1B\x61\x01"  # 居中对齐
            content += "感谢惠顾\n"
            content += "\n\n\n"  # 留出空白以便撕纸
            content += "\x1B\x69"  # 切纸命令
            
            # 合并所有命令到bytes
            print_data = content.encode('gbk')

            return print_raw(printer_config.name, print_data)
        except Exception as e:
            logger.error(f"打印小票失败: {str(e)}")
            raise

    def print_label(data: PrintLabelData):
        """打印标签"""
        try:
            printer_config = printer_settings.get_printer_config("label")
            if not printer_config or not printer_config.name:
                raise ValueError("请先配置标签打印机")
            
            # 构建TSPL打印命令
            commands = []
            # 初始化打印机设置
            commands.append(b'SIZE 40 mm, 30 mm\n')  # 设置标签大小
            commands.append(b'GAP 2 mm, 0 mm\n')     # 设置标签间隙
            commands.append(b'DIRECTION 1\n')         # 打印方向
            commands.append(b'CLS\n')                 # 清除图像缓冲区
            
            # 设置文本打印
            # 商品名称 - 居中大字体
            commands.append(b'TEXT 10,20,"TSS24.BF2",0,2,2,"')  # x,y坐标,字体,旋转,放大倍数x,放大倍数y
            commands.append(data.name.encode('gbk'))
            commands.append(b'"\n')
            
            # 价格信息
            commands.append(b'TEXT 10,100,"TSS24.BF2",0,1,1,"')
            commands.append(f"RMB {data.price:.2f}".encode('gbk'))
            commands.append(b'"\n')
            
            # 打印命令
            commands.append(b'PRINT 1\n')            # 打印份数
        
            # 合并所有命令
            print_data = b''.join(commands)
            
            return print_raw(printer_config.name, print_data)
        except Exception as e:
            logger.error(f"打印标签失败: {str(e)}")
            raise

    @app.on_event("startup")
    async def startup_event():
        try:
            init_database()
            
            # 获取系统打印机列表
            printers = get_system_printers()
            
            # 如果有默认打印机且尚未配置小票打印机，则设置默认打印机为小票打印机
            receipt_config = printer_settings.get_printer_config("receipt")
            if not receipt_config.name:
                default_printer = next((p["name"] for p in printers if p["is_default"]), None)
                if default_printer:
                    printer_settings.update_printer_config(
                        "receipt", 
                        PrinterConfig(name=default_printer, is_default=True)
                    )
                    logger.info(f"已设置默认打印机为小票打印机: {default_printer}")
            
            logger.info("打印机配置初始化完成")
        except Exception as e:
            logger.error(f"启动事件处理失败: {str(e)}")
            logger.error(traceback.format_exc())
    # 修改打印机配置路由
    @api_app.put("/printer/config/{printer_type}")
    async def update_printer_config(printer_type: str, config: PrinterConfig):
        """更新打印机配置"""
        try:
            # 验证打印机是否存在
            printers = get_system_printers()
            printer_names = [p["name"] for p in printers]
            if config.name not in printer_names:
                raise HTTPException(status_code=400, detail=f"打印机 '{config.name}' 未找到")
            
            printer_settings.update_printer_config(printer_type, config)
            return {"message": f"{config.name}配置更新成功"}
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @api_app.get("/printer/config")
    async def get_printer_configs():
        """获取所有打印机配置"""
        return printer_settings.get_all_settings()

    # 添加获取系统打印机列表的路由
    @api_app.get("/printer/system-printers")
    async def get_system_printer_list():
        """获取系统中的打印机列表"""
        try:
            return get_system_printers()
        except Exception as e:
            logger.error(f"获取系统打印机列表失败: {str(e)}")
            return []


    # 修改登录接口
    @api_app.post("/token")
    async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
        try:
            user = auth.authenticate_user(db, form_data.username, form_data.password)
            if not user:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail={
                        "message": "用户名或密码错误",
                        "type": "invalid_credentials"
                    },
                    headers={"WWW-Authenticate": "Bearer"},
                )
            access_token = auth.create_access_token(data={"sub": user.username})
            return {
                "access_token": access_token, 
                "token_type": "bearer",
                "message": "登录成功"
            }
        except Exception as e:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail={
                    "message": "登录失败，请稍后重试",
                    "type": "login_error"
                }
            )

    @app.get("/users/me")
    async def read_users_me(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
        try:
            payload = jwt.decode(token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
            username: str = payload.get("sub")
            if username is None:
                raise HTTPException(status_code=401, detail="Invalid authentication credentials")
        except JWTError:
            raise HTTPException(status_code=401, detail="Invalid authentication credentials")
        user = db.query(models.User).filter(models.User.username == username).first()
        if user is None:
            raise HTTPException(status_code=404, detail="User not found")
        return user

    # 获取当前用户信息
    @api_app.get("/users/me", response_model=UserResponse)
    async def get_current_user(
        current_user: models.User = Depends(auth.get_current_user)
    ):
        return {"username": current_user.username}

    # 修改创建包房的API
    @api_app.post("/rooms", response_model=dict)
    async def create_room(room: RoomCreate, db: Session = Depends(get_db)):
        db_room = db.query(TimedRoom).filter(TimedRoom.name == room.name).first()
        if db_room:
            raise HTTPException(status_code=400, detail="包房名已存在")
        
        new_room = TimedRoom(**room.dict())
        db.add(new_room)
        db.commit()
        db.refresh(new_room)
        
        # 使用 Pydantic 模型序列化响应
        room_response = RoomResponse(
            id=new_room.id,
            name=new_room.name,
            minimum_charge=float(format(new_room.minimum_charge, '.2f')),
            minimum_hours=float(format(new_room.minimum_hours, '.2f')),
            overtime_rate=float(format(new_room.overtime_rate, '.2f')),
            status=new_room.status
        )
        
        return {
            "message": "创建成功",
            "room": room_response.model_dump()
        }

    # 获取所有包房
    @api_app.get("/rooms", response_model=List[dict])
    async def get_rooms(db: Session = Depends(get_db)):
        rooms = db.query(TimedRoom).all()
        return [
            {
                "id": room.id,
                "name": room.name,
                "minimum_charge": room.minimum_charge,
                "minimum_hours": room.minimum_hours,
                "overtime_rate": room.overtime_rate,
                "status": room.status
            }
            for room in rooms
        ]

    # 修改更新包房信息的API
    @api_app.put("/rooms/{room_id}", response_model=dict)
    async def update_room(
        room_id: int,
        room: RoomUpdate,
        db: Session = Depends(get_db)
    ):
        room_db = db.query(TimedRoom).filter(TimedRoom.id == room_id).first()
        if not room_db:
            raise HTTPException(status_code=404, detail="包房不存在")
        
        room_data = room.dict(exclude_unset=True)
        if room_data.get('status') and room_data['status'] not in [e.value for e in RoomStatus]:
            raise HTTPException(status_code=400, detail="无效的状态值")
        
        for key, value in room_data.items():
            setattr(room_db, key, value)
        
        db.commit()
        db.refresh(room_db)
        
        # 使用 Pydantic 模型序列化响应
        room_response = RoomResponse(
            id=room_db.id,
            name=room_db.name,
            minimum_charge=float(format(room_db.minimum_charge, '.2f')),
            minimum_hours=float(format(room_db.minimum_hours, '.2f')),
            overtime_rate=float(format(room_db.overtime_rate, '.2f')),
            status=room_db.status
        )
        
        return {
            "message": "更新成功",
            "room": room_response.model_dump()
        }

    # 删除包房
    @api_app.delete("/rooms/{room_id}", response_model=dict)
    async def delete_room(room_id: int, db: Session = Depends(get_db)):
        # 检查是否有关联订单
        has_orders = db.query(models.Order).filter(models.Order.room_id == room_id).first()
        if has_orders:
           raise HTTPException(status_code=400, detail="无法删除已有订单的房间")
       
        room = db.query(TimedRoom).filter(TimedRoom.id == room_id).first()
        if not room:
            raise HTTPException(status_code=404, detail="包房不存在")
        
        db.delete(room)
        db.commit()
        return {"message": "删除成功"}

    # 修改创建零食的接口
    @api_app.post("/snacks/", response_model=dict)
    async def create_snack(snack: SnackCreate, db: Session = Depends(get_db)):
        db_snack = db.query(models.Snack).filter(models.Snack.name == snack.name).first()
        if db_snack:
            raise HTTPException(status_code=400, detail="零食名称已存在")
        
        new_snack = models.Snack(**snack.dict())
        db.add(new_snack)
        db.commit()
        db.refresh(new_snack)
        
        # 使用 SnackResponse 模型序列化响应
        snack_response = SnackResponse(
            id=new_snack.id,
            name=new_snack.name,
            price=float(format(new_snack.price, '.2f')),
            cost=float(format(new_snack.cost, '.2f')),
            stock=new_snack.stock,
            unit=new_snack.unit,
            category_id=new_snack.category_id,
            category=new_snack.category,
            description=new_snack.description,
            is_active=new_snack.is_active
        )
        
        return {
            "message": "创建成功",
            "snack": snack_response.model_dump()
        }

    # 获取所有零食
    @api_app.get("/snacks/", response_model=List[SnackResponse])
    async def get_snacks(db: Session = Depends(get_db)):
        snacks = db.query(models.Snack).all()
        return [
            SnackResponse(
                id=snack.id,
                name=snack.name,
                price=snack.price,
                cost=snack.cost,
                stock=snack.stock,
                unit=snack.unit,
                category_id=snack.category_id,
                category=snack.category,  # 传入完整的 category 对象
                description=snack.description,
                is_active=snack.is_active
            )
            for snack in snacks
        ]

    # 修改更新零食信息的接口
    @api_app.put("/snacks/{snack_id}", response_model=dict)
    async def update_snack(
        snack_id: int,
        snack: SnackUpdate,
        db: Session = Depends(get_db)
    ):
        db_snack = db.query(models.Snack).filter(models.Snack.id == snack_id).first()
        if not db_snack:
            raise HTTPException(status_code=404, detail="零食不存在")
        
        snack_data = snack.dict(exclude_unset=True)
        for key, value in snack_data.items():
            setattr(db_snack, key, value)
        
        db.commit()
        db.refresh(db_snack)
        
        # 使用 SnackResponse 模型序列化响应
        snack_response = SnackResponse(
            id=db_snack.id,
            name=db_snack.name,
            price=float(format(db_snack.price, '.2f')),
            cost=float(format(db_snack.cost, '.2f')),
            stock=db_snack.stock,
            unit=db_snack.unit,
            category_id=db_snack.category_id,
            category=db_snack.category,
            description=db_snack.description,
            is_active=db_snack.is_active
        )
        
        return {
            "message": "更新成功",
            "snack": snack_response.model_dump()
        }

    # 修改调整库存的接口
    @api_app.put("/snacks/stock/{snack_id}", response_model=dict)
    async def adjust_stock(
        snack_id: int,
        adjustment: StockAdjustment,  # 使用请求体接收参数
        db: Session = Depends(get_db)
    ):
        snack = db.query(models.Snack).filter(models.Snack.id == snack_id).first()
        if not snack:
            raise HTTPException(status_code=404, detail="零食不存在")
        
        new_stock = snack.stock + adjustment.adjustment
        if new_stock < 0:
            raise HTTPException(status_code=400, detail="库存不足")
        
        snack.stock = new_stock
        db.commit()
        db.refresh(snack)
        
        # 使用 Pydantic 模型序列化响应
        snack_response = SnackResponse(
            id=snack.id,
            name=snack.name,
            price=float(format(snack.price, '.2f')),
            cost=float(format(snack.cost, '.2f')),
            stock=snack.stock,
            unit=snack.unit,
            category_id=snack.category_id,
            category=snack.category,
            description=snack.description,
            is_active=snack.is_active
        )
        
        return {
            "message": "库存调整成功",
            "snack": snack_response.model_dump()
        }

    # 删除零食
    @api_app.delete("/snacks/{snack_id}", response_model=dict)
    async def delete_snack(snack_id: int, db: Session = Depends(get_db)):
        snack = db.query(models.Snack).filter(models.Snack.id == snack_id).first()
        if not snack:
            raise HTTPException(status_code=404, detail="零食不存在")
        
        db.delete(snack)
        db.commit()
        return {"message": "删除成功"}

    # 获取结算记录
    @api_app.get("/orders/history")
    async def get_order_history(db: Session = Depends(get_db)):
        orders = db.query(models.Order).filter(
            models.Order.status == "completed"
        ).order_by(models.Order.end_time.desc()).all()
        
        result = []
        for order in orders:
            items = [
                {
                    "id": item.id,
                    "snack_name": item.snack.name,
                    "quantity": item.quantity,
                    "price": float(format(item.price, '.2f')),
                    "subtotal": float(format(item.price * item.quantity, '.2f')),
                    "created_at": item.created_at
                }
                for item in order.order_items
            ]
            
            duration = (order.end_time - order.start_time).total_seconds() / 3600
            base_amount = float(format(order.base_amount, '.2f'))
            snack_amount = float(format(sum(item["subtotal"] for item in items), '.2f'))
            adjustment = float(format(order.adjustment, '.2f'))
            total_amount = float(format(base_amount + snack_amount + adjustment, '.2f'))
            
            if not order.room:
                room_name = "已删除"
            else:
                room_name = order.room.name

            order_data = {
                "id": order.id,
                "room_name": room_name,
                "start_time": order.start_time,
                "end_time": order.end_time,
                "duration": float(format(duration, '.2f')),
                "base_amount": base_amount,
                "items": items,
                "snack_amount": snack_amount,
                "adjustment": adjustment,
                "remark": order.remark,
                "total_amount": total_amount
            }
            result.append(order_data)
        
        return JSONResponse(
            content=json.loads(
                json.dumps(result, cls=DecimalEncoder)
            )
        )

    # 修改创建订单的接口
    @api_app.post("/orders/", response_model=dict)
    async def create_order(order: OrderCreate, db: Session = Depends(get_db)):
        # 检查包房状态
        room = db.query(models.TimedRoom).filter(models.TimedRoom.id == order.room_id).first()
        if not room:
            raise HTTPException(status_code=404, detail="包房不存在")
        if room.status != RoomStatus.AVAILABLE.value:
            raise HTTPException(status_code=400, detail="包房不可用")
        
        # 创建订单，使用中国时区
        new_order = models.Order(
            room_id=order.room_id,
            start_time=datetime.now(CHINA_TZ)  # 使用中国时区创建开始时间
        )
        db.add(new_order)
        
        # 更新包房状态
        room.status = RoomStatus.OCCUPIED.value
        
        db.commit()
        db.refresh(new_order)
        
        # 使用 Pydantic 模型序列化响应
        order_response = OrderResponse(
            id=new_order.id,
            room_id=new_order.room_id,
            start_time=new_order.start_time,
            end_time=new_order.end_time,
            base_amount=float(format(new_order.base_amount, '.2f')),
            total_amount=float(format(new_order.total_amount, '.2f')),
            status=new_order.status
        )

        logger.info(f'开台成功: {order_response.model_dump()}')
        
        return {
            "message": "开房成功",
            "order": order_response.model_dump()
        }

    # 修改添加零食到订单的接口
    @api_app.post("/orders/{order_id}/items", response_model=dict)
    async def add_order_item(
        order_id: int,
        item: OrderItemCreate,
        db: Session = Depends(get_db)
    ):
        # 检查订单
        order = db.query(models.Order).filter(models.Order.id == order_id).first()
        if not order or order.status != "active":
            raise HTTPException(status_code=400, detail="订单不存在或已结算")
        
        # 检查零食
        snack = db.query(models.Snack).filter(models.Snack.id == item.snack_id).first()
        if not snack:
            raise HTTPException(status_code=404, detail="零食不存在")
        if snack.stock < item.quantity:
            raise HTTPException(status_code=400, detail="库存不足")
        
        # 创建订单项
        order_item = models.OrderItem(
            order_id=order_id,
            snack_id=item.snack_id,
            quantity=item.quantity,
            price=snack.price
        )
        db.add(order_item)
        
        # 更新库存
        snack.stock -= item.quantity
        
        db.commit()
        db.refresh(order_item)
        
        # 使用 Pydantic 模型序列化响应
        response_item = OrderItemResponse(
            id=order_item.id,
            order_id=order_item.order_id,
            snack_id=order_item.snack_id,
            quantity=order_item.quantity,
            price=float(format(order_item.price, '.2f')),
            created_at=order_item.created_at,
            snack=snack
        )
        
        return {
            "message": "添加成功",
            "order_item": response_item.model_dump()
        }

    # 结算订单
    @api_app.post("/orders/{order_id}/checkout", response_model=dict)
    async def checkout_order(
        order_id: int, 
        checkout_data: CheckoutData,
        db: Session = Depends(get_db)
    ):
        # 获取订单
        order = db.query(models.Order).filter(models.Order.id == order_id).first()
        if not order or order.status != "active":
            raise HTTPException(status_code=400, detail="订单不存在或已结算")
        
        # 计算包房费用
        end_time = datetime.now()
        duration = (end_time - order.start_time).total_seconds() / 3600  # 小时
        room = order.room
        
        if duration <= room.minimum_hours:
            base_amount = room.minimum_charge
            overtime = 0
        else:
            overtime = duration - room.minimum_hours
            # 使用函数计算超时费
            _, overtime_fee = calculate_overtime_fee(
                duration=duration,
                minimum_hours=room.minimum_hours,
                overtime_rate=room.overtime_rate
            )
            base_amount = room.minimum_charge + overtime_fee
        
        # 计算零食费用
        snack_amount = sum(item.price * item.quantity for item in order.order_items)
        
        # 更新订单
        order.end_time = end_time
        order.base_amount = base_amount
        order.total_amount = base_amount + snack_amount + checkout_data.adjustment
        order.adjustment = checkout_data.adjustment
        order.remark = checkout_data.remark
        order.status = "completed"
        
        # 更新包房状态
        room.status = RoomStatus.AVAILABLE.value
        
        db.commit()
        db.refresh(order)
        return {
            "message": "结算成功",
            "order": {
                "id": order.id,
                "duration": round(duration, 2),
                "base_amount": round(base_amount, 2),
                "snack_amount": round(snack_amount, 2),
                "total_amount": round(base_amount + snack_amount, 2)
            }
        }

    # 获取订单详情
    @api_app.get("/orders/{order_id}", response_model=dict)
    async def get_order(order_id: int, db: Session = Depends(get_db)):
        order = db.query(models.Order).filter(models.Order.id == order_id).first()
        if not order:
            raise HTTPException(status_code=404, detail="订单不存在")
        
        items = [
            {
                "id": item.id,
                "snack_name": item.snack.name,
                "quantity": item.quantity,
                "price": item.price,
                "subtotal": item.price * item.quantity
            }
            for item in order.order_items
        ]
        
        return {
            "id": order.id,
            "room_name": order.room.name,
            "start_time": order.start_time,
            "end_time": order.end_time,
            "status": order.status,
            "base_amount": order.base_amount,
            "total_amount": order.total_amount,
            "items": items
        }

    # 获取房间的当前订单
    @api_app.get("/rooms/{room_id}/current-order", response_model=dict)
    async def get_room_current_order(room_id: int, db: Session = Depends(get_db)):
        room = db.query(models.TimedRoom).filter(models.TimedRoom.id == room_id).first()
        if not room:
            raise HTTPException(status_code=404, detail="包房不存在")
        
        order = db.query(models.Order).filter(
            models.Order.room_id == room_id,
            models.Order.status == "active"
        ).first()
        
        if not order:
            raise HTTPException(status_code=404, detail="没有进行中的订单")
        
        return {
            "id": order.id,
            "room_id": order.room_id,
            "start_time": order.start_time,
            "end_time": order.end_time,
            "base_amount": order.base_amount,
            "total_amount": order.total_amount,
            "status": order.status
        }

    # 获取所有包房的实时状态
    @api_app.get("/rooms/status", response_model=List[dict])
    async def get_rooms_status(db: Session = Depends(get_db)):
        rooms = db.query(TimedRoom).all()
        result = []
        
        for room in rooms:
            room_data = {
                "id": room.id,
                "name": room.name,
                "minimum_charge": room.minimum_charge,
                "minimum_hours": room.minimum_hours,
                "overtime_rate": room.overtime_rate,
                "status": room.status,
                "currentOrder": None
            }
            
            # 如果房间在使用中，获取当前订单信息
            if room.status == RoomStatus.OCCUPIED.value:
                current_order = db.query(models.Order).filter(
                    models.Order.room_id == room.id,
                    models.Order.status == "active"
                ).order_by(models.Order.start_time.desc()).first()
                
                if current_order:
                    # 计算当前使用时长和费用
                    now = datetime.now(CHINA_TZ)
                    start_time = current_order.start_time
                    
                    # 如果 start_time 是无时区的，假设它是 UTC 时间并设置时区
                    if start_time.tzinfo is None:
                        start_time = start_time.replace(tzinfo=CHINA_TZ)
                    else:
                        start_time = start_time.astimezone(CHINA_TZ)    

                    duration = (now - start_time).total_seconds() / 3600
                    
                    # 计算包房费用
                    if duration <= room.minimum_hours:
                        current_base_amount = room.minimum_charge
                        overtime = 0
                    else:
                        overtime = duration - room.minimum_hours
                        # 使用函数计算超时费
                        _, overtime_fee = calculate_overtime_fee(
                            duration=duration,
                            minimum_hours=room.minimum_hours,
                            overtime_rate=room.overtime_rate
                        )
                        current_base_amount = room.minimum_charge + overtime_fee
                    
                    # 获取订单项
                    items = [
                        {
                            "id": item.id,
                            "snack_name": item.snack.name,
                            "quantity": item.quantity,
                            "price": item.price,
                            "subtotal": item.price * item.quantity,
                            "created_at": item.created_at
                        }
                        for item in current_order.order_items
                    ]
                    
                    # 计算零食总额
                    snack_amount = sum(item["subtotal"] for item in items)
                    
                    room_data["currentOrder"] = {
                        "id": current_order.id,
                        "start_time": start_time,
                        "duration": round(duration, 2),
                        "overtime": round(overtime, 2) if overtime > 0 else 0,
                        "current_base_amount": round(current_base_amount, 2),
                        "items": items,
                        "snack_amount": round(snack_amount, 2),
                        "current_total_amount": round(current_base_amount + snack_amount, 2)
                    }
            
            result.append(room_data)
        
        return result

    # 预结算（获取结算金额但不实际结算）
    @api_app.get("/orders/{order_id}/pre-checkout", response_model=dict)
    async def pre_checkout_order(order_id: int, db: Session = Depends(get_db)):
        # 获取订单
        order = db.query(models.Order).filter(models.Order.id == order_id).first()
        if not order or order.status != "active":
            raise HTTPException(status_code=400, detail="订单不存在或已结算")
        
        # 计算包房费用
        now = datetime.now()
        duration = (now - order.start_time).total_seconds() / 3600  # 小时
        room = order.room
        
        # 初始化变量
        base_amount = room.minimum_charge  # 基础费用始终为最低消费
        overtime = 0
        overtime_fee = 0
        
        if duration <= room.minimum_hours:
            pass  # 不超时，使用默认值
        else:
            overtime = duration - room.minimum_hours
            # 使用函数计算超时费
            _, overtime_fee = calculate_overtime_fee(
                duration=duration,
                minimum_hours=room.minimum_hours,
                overtime_rate=room.overtime_rate
            )
        
        # 计算零食费用
        snack_amount = sum(item.price * item.quantity for item in order.order_items)
        # 获取订单项
        items = [
            {
                "id": item.id,
                "snack_name": item.snack.name,
                "quantity": item.quantity,
                "price": item.price,
                "subtotal": item.price * item.quantity,
                "created_at": item.created_at
            }
            for item in order.order_items
        ]
        return {
            "message": "预结算成功",
            "order": {
                "id": order.id,
                "duration": float(format(duration, '.2f')),
                "start_time": order.start_time,
                "overtime": float(format(overtime, '.2f')),
                "minimum_charge": float(format(room.minimum_charge, '.2f')),
                "overtime_fee": float(format(overtime_fee, '.2f')),
                "base_amount": float(format(base_amount, '.2f')),
                "snack_amount": float(format(snack_amount, '.2f')),
                "snack_items": items,
                "total_amount": float(format(base_amount + overtime_fee + snack_amount, '.2f'))

            }
        }

    class PasswordChange(BaseModel):
        old_password: str
        new_password: str

    @api_app.post("/users/change-password", response_model=dict)
    async def change_password(
        password_data: PasswordChange,
        token: str = Depends(oauth2_scheme),
        db: Session = Depends(get_db)
    ):
        try:
            payload = jwt.decode(token, auth.SECRET_KEY, algorithms=[auth.ALGORITHM])
            username = payload.get("sub")
            if not username:
                raise HTTPException(status_code=401, detail="无效的认证凭据")
            
            user = db.query(models.User).filter(models.User.username == username).first()
            if not user:
                raise HTTPException(status_code=404, detail="用户不存在")
            
            if not auth.verify_password(password_data.old_password, user.hashed_password):
                raise HTTPException(status_code=400, detail="原密码错误")
            
            user.hashed_password = auth.get_password_hash(password_data.new_password)
            db.commit()
            
            return {"message": "密码修改成功"}
        except JWTError:
            raise HTTPException(status_code=401, detail="无效的认证凭据")

    def get_rooms_with_orders(rooms: List[models.TimedRoom], db: Session) -> List[Dict]:
        result = []
        for room in rooms:
            room_data = {
                "id": room.id,
                "name": room.name,
                "minimum_charge": float(format(room.minimum_charge, '.2f')),
                "minimum_hours": float(format(room.minimum_hours, '.2f')),
                "overtime_rate": float(format(room.overtime_rate, '.2f')),
                "status": room.status,
                "currentOrder": None
            }
            
            # 如果包房正在使用中，获取当前订单信息
            if room.status == RoomStatus.OCCUPIED.value:
                current_order = db.query(models.Order).filter(
                    models.Order.room_id == room.id,
                    models.Order.status == "active"
                ).first()
                
                if current_order:
                    # 使用中国时区的当前时间
                    now = datetime.now(CHINA_TZ)
                    start_time = current_order.start_time
                    
                    # 确保 start_time 有正确的时区信息
                    if start_time.tzinfo is None:
                        start_time = start_time.replace(tzinfo=CHINA_TZ)
                    else:
                        start_time = start_time.astimezone(CHINA_TZ)
                    
                    # 计算当前时长和费用
                    duration = (now - start_time).total_seconds() / 3600
                    
                    # 计算基础费用和超时费
                    if duration <= room.minimum_hours:
                        current_base_amount = room.minimum_charge
                        overtime = 0
                    else:
                        overtime = duration - room.minimum_hours
                        # 使用 calculate_overtime_fee 函数计算超时费用
                        _, overtime_fee = calculate_overtime_fee(
                            duration=duration,
                            minimum_hours=room.minimum_hours,
                            overtime_rate=room.overtime_rate
                        )
                        current_base_amount = room.minimum_charge + overtime_fee
                    
                    # 获取零食信息
                    items = [
                        {
                            "id": item.id,
                            "snack_name": item.snack.name,
                            "quantity": item.quantity,
                            "price": float(format(item.price, '.2f')),
                            "subtotal": float(format(item.price * item.quantity, '.2f')),
                            "created_at": item.created_at
                        }
                        for item in current_order.order_items
                    ]
                    
                    # 计算零食总额
                    snack_amount = sum(item["subtotal"] for item in items)
                    
                    room_data["currentOrder"] = {
                        "id": current_order.id,
                        "start_time": start_time,
                        "duration": float(format(duration, '.2f')),
                        "overtime": float(format(overtime, '.2f')),
                        "current_base_amount": float(format(current_base_amount, '.2f')),
                        "items": items,
                        "snack_amount": float(format(snack_amount, '.2f')),
                        "current_total_amount": float(format(current_base_amount + snack_amount, '.2f'))
                    }
            
            result.append(room_data)
        return result

    # 获取单个包房信息
    @api_app.get("/rooms/{room_id}")
    async def get_room(room_id: int, db: Session = Depends(get_db)):
        room = db.query(models.TimedRoom).filter(models.TimedRoom.id == room_id).first()
        if not room:
            raise HTTPException(status_code=404, detail="包房不存在")
        
        # 使用相同的函数处理包房信息
        rooms_info = get_rooms_with_orders([room], db)
        return rooms_info[0] if rooms_info else None

    # API路由
    @api_app.get("/test")
    async def test():
        return {"message": "Hello from FastAPI"}

    # 添加报表相关路由
    @api_app.get("/reports/daily")
    async def get_daily_report(db: Session = Depends(get_db)):
        try:
            # 获取今日订单
            today = datetime.now().date()
            orders = db.query(models.Order).filter(
                models.Order.status == "completed",
                func.date(models.Order.end_time) == today
            ).all()
            
            # 计算统计数据
            total_amount = sum(order.total_amount for order in orders)
            room_income = sum(order.base_amount for order in orders)
            snack_income = sum(order.total_amount - order.base_amount for order in orders)
            
            return {
                "total_amount": float(format(total_amount, '.2f')),
                "room_income": float(format(room_income, '.2f')),
                "snack_income": float(format(snack_income, '.2f')),
                "order_count": len(orders),
                "orders": orders
            }
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @api_app.get("/reports/range")
    async def get_report_by_range(
        start_date: str,
        end_date: str,
        db: Session = Depends(get_db)
    ):
        try:
            start = datetime.strptime(start_date, '%Y-%m-%d')
            end = datetime.strptime(end_date, '%Y-%m-%d') + timedelta(days=1)
            
            orders = db.query(models.Order).filter(
                models.Order.status == "completed",
                models.Order.end_time >= start,
                models.Order.end_time < end
            ).all()

            # 处理订单数据，包括零食费用
            orders_data = []
            total_base_amount = 0
            total_snack_amount = 0
            total_adjustment = 0
            
            for order in orders:
                # 计算订单的零食总额
                snack_amount = sum(item.price * item.quantity for item in order.order_items)
                
                if not order.room:
                    room_name = "已删除"
                else:
                    room_name = order.room.name

                order_data = {
                    "id": order.id,
                    "room_name": room_name,
                    "start_time": order.start_time,
                    "end_time": order.end_time,
                    "base_amount": float(format(order.base_amount, '.2f')),
                    "snack_amount": float(format(snack_amount, '.2f')),
                    "adjustment": float(format(order.adjustment, '.2f')),
                    "total_amount": float(format(order.total_amount, '.2f'))
                }
                orders_data.append(order_data)
                
                # 累加总额
                total_base_amount += order.base_amount
                total_snack_amount += snack_amount
                total_adjustment += order.adjustment
            
            return {
                "orders": orders_data,
                "summary": {
                    "total_base_amount": float(format(total_base_amount, '.2f')),
                    "total_snack_amount": float(format(total_snack_amount, '.2f')),
                    "total_adjustment": float(format(total_adjustment, '.2f')),
                    "total_amount": float(format(total_base_amount + total_snack_amount + total_adjustment, '.2f')),
                    "order_count": len(orders)
                }
            }
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @api_app.get("/reports/statistics")
    async def get_statistics(db: Session = Depends(get_db)):
        try:
            # 获取今日数据
            today = datetime.now().date()
            today_orders = db.query(models.Order).filter(
                models.Order.status == "completed",
                func.date(models.Order.end_time) == today
            ).all()
            
            # 获取本月数据
            first_day = today.replace(day=1)
            month_orders = db.query(models.Order).filter(
                models.Order.status == "completed",
                models.Order.end_time >= first_day
            ).all()
            
            return {
                "today": {
                    "income": sum(order.total_amount for order in today_orders),
                    "orders": len(today_orders)
                },
                "month": {
                    "income": sum(order.total_amount for order in month_orders),
                    "orders": len(month_orders)
                }
            }
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    # 添加分类相关的路由
    @api_app.get("/categories", response_model=List[CategoryResponse])
    async def get_categories(db: Session = Depends(get_db)):
        return db.query(models.Category).all()

    @api_app.post("/categories", response_model=CategoryResponse)
    async def create_category(category: CategoryCreate, db: Session = Depends(get_db)):
        db_category = models.Category(name=category.name)
        try:
            db.add(db_category)
            db.commit()
            db.refresh(db_category)
            return db_category
        except IntegrityError:
            db.rollback()
            raise HTTPException(status_code=400, detail="分类名称已存在")

    @api_app.put("/categories/{category_id}", response_model=CategoryResponse)
    async def update_category(
        category_id: int,
        category: CategoryUpdate,
        db: Session = Depends(get_db)
    ):
        db_category = db.query(models.Category).filter(models.Category.id == category_id).first()
        if not db_category:
            raise HTTPException(status_code=404, detail="分类不存在")
        
        try:
            db_category.name = category.name
            db.commit()
            db.refresh(db_category)
            return db_category
        except IntegrityError:
            db.rollback()
            raise HTTPException(status_code=400, detail="分类名称已存在")

    @api_app.delete("/categories/{category_id}")
    async def delete_category(category_id: int, db: Session = Depends(get_db)):
        db_category = db.query(models.Category).filter(models.Category.id == category_id).first()
        if not db_category:
            raise HTTPException(status_code=404, detail="分类不存在")
        
        # 检查是否有零食使用此分类
        if db.query(models.Snack).filter(models.Snack.category_id == category_id).first():
            raise HTTPException(status_code=400, detail="无法删除已被使用的分类")
        
        db.delete(db_category)
        db.commit()
        return {"message": "删除成功"}

    @api_app.delete("/orders/{order_id}/items/{item_id}")
    async def delete_order_item(
        order_id: int,
        item_id: int,
        db: Session = Depends(get_db)
    ):
        # 查找订单项
        order_item = db.query(models.OrderItem).filter(
            models.OrderItem.order_id == order_id,
            models.OrderItem.id == item_id
        ).first()
        
        if not order_item:
            raise HTTPException(status_code=404, detail="订单项不存在")
        
        # 检查订单状态
        order = db.query(models.Order).filter(models.Order.id == order_id).first()
        if not order or order.status != "active":
            raise HTTPException(status_code=400, detail="订单已结束，无法修改")
        
        try:
            # 恢复库存
            snack = db.query(models.Snack).filter(models.Snack.id == order_item.snack_id).first()
            if snack:
                snack.stock += order_item.quantity
            
            # 删除订单项
            db.delete(order_item)
            db.commit()
            
            return {"message": "删除成功"}
        except Exception as e:
            db.rollback()
            raise HTTPException(status_code=500, detail=str(e))

    # 修改打印相关的路由
    @api_app.post("/print/receipt")
    async def print_order_receipt(data: PrintReceiptData):
        """打印小票"""
        try:
            success = print_receipt(data)
            return {"message": "打印成功" if success else "打印失败"}
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @api_app.post("/print/label")
    async def print_product_label(data: PrintLabelData):
        """打印标签"""
        try:
            success = print_label(data)
            return {"message": "打印成功" if success else "打印失败"}
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    if __name__ == "__main__":
        try:
            import uvicorn
            logger.info("Starting uvicorn server...")
            uvicorn.run(
                app,
                host="127.0.0.1",
                port=8000,
                log_level="info"
            )
        except Exception as e:
            logger.error("Error starting server:")
            logger.error(traceback.format_exc())
            input("Press Enter to exit...")
except Exception as e:
    logger.error("Error during startup:")
    logger.error(traceback.format_exc())
    input("Press Enter to exit...")
    sys.exit(1)

